package com.brush.framework.web.service;

import com.brush.framework.web.service.AdminTokenService;
import com.brush.common.constant.CacheConstants;
import com.brush.common.constant.Constants;
import com.brush.common.core.domain.entity.SysUser;
import com.brush.common.core.domain.req.AdminLoginReq;
import com.brush.common.core.domain.resp.AdminUserDetails;
import com.brush.common.exception.ServiceException;
import com.brush.common.exception.user.BlackListException;
import com.brush.common.exception.user.CaptchaException;
import com.brush.common.exception.user.CaptchaExpireException;
import com.brush.common.exception.user.UserPasswordNotMatchException;
import com.brush.common.utils.MessageUtils;
import com.brush.common.utils.ip.IpUtils;
import com.brush.framework.manager.AsyncManager;
import com.brush.framework.manager.factory.AsyncTimerTaskFactory;
import com.brush.system.service.SysConfigService;
import com.brush.system.service.SysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.Objects;

/**
 * 后台登录业务逻辑类
 */
@Component
public class AdminLoginService {

    /**
     * 令牌管理对象
     */
    @Autowired
    private AdminTokenService adminTokenService;

    /**
     * spring security 认证管理器
     */
    @Qualifier("adminAuthenticationManager")
    @Autowired
    private AuthenticationManager adminAuthenticationManager;

    /**
     * redis 操作对象
     */
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 引用sysConfig业务逻辑层
     */
    @Autowired
    private SysConfigService sysConfigService;

    /**
     * 引用sys_user业务逻辑层
     */
    @Autowired
    private SysUserService sysUserService;

    /**
     * 后台登录业务逻辑
     *
     * @param adminLoginReq
     * @return
     */
    public String login(AdminLoginReq adminLoginReq) {
        //1、判断验证码是否正确
        this.checkCaptcha(adminLoginReq.getUuid(), adminLoginReq.getCode());
        //2、登录判断，当前IP是不是黑白单中
        String blackIp = this.sysConfigService.getConfigValueByKey("sys.login.blackIPList");
        // 判断当前IP是否在黑名单中
        if (IpUtils.isMatchedIp(blackIp, IpUtils.getIpAddr())) {
            throw new BlackListException();
        }

        // 3、使用spring security框架，按它的规范来写登录代码
        // 认证接口
        Authentication authentication = null;

        try {
            //spring security给我配置的登录类
            UsernamePasswordAuthenticationToken usernamePasswordToken =
                    new UsernamePasswordAuthenticationToken(adminLoginReq.getUsername(), adminLoginReq.getPassword());

            //调用登录流程,调用自定义的 UserDetailsService接口
            authentication = this.adminAuthenticationManager.authenticate(usernamePasswordToken);

        } catch (Exception e) {
            // 密码失败的异常
            if (e instanceof org.springframework.security.authentication.BadCredentialsException) {
                //记录登录失败原因到sys_logininfor表中
                AsyncManager.me().execute(AsyncTimerTaskFactory.recordLogininfor(adminLoginReq.getUsername(),
                        Constants.LOGIN_FAIL,
                        MessageUtils.message("user.password.not.match")));

                throw new UserPasswordNotMatchException();
            } else {
                //记录登录失败原因到sys_logininfor表中
                AsyncManager.me().execute(AsyncTimerTaskFactory.recordLogininfor(adminLoginReq.getUsername(),
                        Constants.LOGIN_FAIL,
                        e.getMessage()));
                throw new ServiceException(e.getMessage());
            }
        }

        // 认证成功了, 写入登录志，更改最新登录时间 以及 生成令牌

        // 1、向登录日志表记录成功信息
        AsyncManager.me().execute(AsyncTimerTaskFactory.recordLogininfor(adminLoginReq.getUsername(),
                Constants.LOGIN_SUCCESS,
                MessageUtils.message("user.login.success")));

        // 得到当前登录的用户
        AdminUserDetails adminUserDetails = (AdminUserDetails) authentication.getPrincipal();

        //2、记录最后登录时间和ip
        SysUser updateUser = new SysUser();
        updateUser.setUserId(adminUserDetails.getUserId());
        updateUser.setLoginIp(adminUserDetails.getIpaddr());
        updateUser.setLoginDate(new Date());
        updateUser.setUpdateBy(adminLoginReq.getUsername());
        updateUser.setUpdateTime(new Date());
        this.sysUserService.updateById(updateUser);

        //3、换令牌
        String token = this.adminTokenService.createToken(adminUserDetails);

        return token;
    }

    /**
     * 判断验证码是否正确
     *
     * @param uuid
     * @param code
     */
    public void checkCaptcha(String uuid, String code) {
        String redisKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
        //获取redis中的验证码
        Object redisValue = this.redisTemplate.opsForValue().get(redisKey);
        // 如果为null
        if (Objects.isNull(redisValue)) {
            throw new CaptchaExpireException();
        }

        // 从redis中删除验证码
        this.redisTemplate.delete(redisKey);

        // 判断验证码是否正确
        if (!code.equals(redisValue)) {
            throw new CaptchaException();
        }
    }


}
